<?php

namespace App\Http\Controllers;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesResources;
use DB;

class Controller extends BaseController
{
    use AuthorizesRequests, AuthorizesResources, DispatchesJobs, ValidatesRequests;

    protected function formatSmsCodeOutput($result)
    {
        $result['ResponseCode']=200;
        $result['ResponseMsg']='OK';
        return  $result;
    }
    protected function formatOutput($result)
    {
        return [
            'msg' => [
                'code' => 0,
                'info' => '',
            ],
            'data' => $result,
        ];
    }

    public function buildQuery(Model $model, array $params)
    {

        //group
        $groups = array_get($params, '_groups');
        $groups = empty($groups) ? [] : explode(',', $groups);

        //field
        $fields_raw = array_get($params, '_fields', '*');
        $fields = explode(',', $fields_raw);

        if (!empty($groups) and array_get($params, '_group_count_total')) {
            $query = $model->select(DB::raw("SQL_CALC_FOUND_ROWS $fields_raw"));
        } else {
            $query = $model->select($fields);
        }

        //sort
        $sorts = array_get($params, '_sort');
        if (is_array($sorts)) {
            foreach ($sorts as $field => $direction) {
                $direction = $direction < 0 ? 'desc' : 'asc';
                $query->orderBy($field, $direction);
            }
        }

        //where
        $operations = [
            'e' => '=',
            'lte' => '<=',
            'gte' => '>=',
            'ne' => '<>',
            'lt' => '<',
            'gt' => '>',
        ];
        foreach ($params as $key => $val) {
            if (is_null($val) or strpos($key, '_') === 0) {
                continue;
            }

            $__pos = strpos($key, '__');
            if ($__pos > 0) {
                $operation = substr($key, $__pos + 2);
                $key = substr($key, 0, $__pos);
                switch ($operation) {
                    case 'in':
                        if (!is_array($val)) {
                            $val = explode(',', $val);
                        }
                        $query->whereIn($key, $val);
                        break;
                    case 'notin':
                        if (!is_array($val)) {
                            $val = explode(',', $val);
                        }
                        $query->whereNotIn($key, $val);
                        break;
                    case 'e':
                    case 'lte':
                    case 'gte':
                    case 'ne':
                    case 'lt':
                    case 'gt':
                        $query->where($key, $operations[$operation], $val);
                        break;
                    case 'null':
                        $query->whereNull($key);
                        break;
                    case 'notnull':
                        $query->whereNotNull($key);
                        break;
                    case 'like':
                        $query->where($key, 'like', $val);
                        break;
                    case 'notlike':
                        $query->where($key, 'not like', $val);
                        break;
                }
            } else {
                $query->where($key, '=', $val);
            }
        }
        if (!empty($groups)) {
            $query->addSelect(DB::raw('count(*) as _count'));
            $query->groupBy($groups);
        }

        return $query;
    }
    
    public function getResult(Builder $query, array $params, $maxPerPage = 120){
        //pegination
        $perPage = (int)array_get($params, '_page_size');
        $perPage = min($perPage, $maxPerPage);
        if (!$perPage) {
            $perPage = $maxPerPage;
        }
        $result['page_size'] = $perPage;

        $page = (int)array_get($params, '_page');
        $page = $page ?: 1;
        $result['page'] = $page;

        unset($params['_page_size']);
        unset($params['_page']);

        $result['count'] = 0;
        //get count before pegination
        if (!array_get($params, '_group')) {
            $result['total'] = $query->count();
        }

        $query->skip(($page - 1) * $perPage);
        $result['list'] = $query->take($perPage)->get()->toArray();

        if (array_get($params, '_group') and array_get($params, '_group_count')) {
            $result['total'] = DB::select(DB::raw('SELECT FOUND_ROWS() as rows;'))[0]->rows;
        }

        foreach ($result['list'] as $index => $row) {
            foreach ($row as $key => $val) {
                if (is_null($val)) {
                    $result['list'][$index][$key] = '';
                }
            }
        }

        return $result;
    }

    public function search(Model $model, array $params, $maxPerPage = 120)
    {
        //pegination
        $perPage = (int)array_get($params, '_page_size');
        $perPage = min($perPage, $maxPerPage);
        if (!$perPage) {
            $perPage = $maxPerPage;
        }
        $result['page_size'] = $perPage;

        $page = (int)array_get($params, '_page');
        $page = $page ?: 1;
        $result['page'] = $page;

        unset($params['_page_size']);
        unset($params['_page']);

        $query = $this->buildQuery($model, $params);

        $result['count'] = 0;
        //get count before pegination
        if (!array_get($params, '_group')) {
            $result['total'] = $query->count();
        }

        $query->skip(($page - 1) * $perPage);
        $result['list'] = $query->take($perPage)->get()->toArray();

        if (array_get($params, '_group') and array_get($params, '_group_count')) {
            $result['total'] = DB::select(DB::raw('SELECT FOUND_ROWS() as rows;'))[0]->rows;
        }

        foreach ($result['list'] as $index => $row) {
            foreach ($row as $key => $val) {
                if (is_null($val)) {
                    $result['list'][$index][$key] = '';
                }
            }
        }

        return $result;
    }


    public function buildMultiQuery(Builder $query, array $params)
    {

        //where
        $operations = [
            'e' => '=',
            'lte' => '<=',
            'gte' => '>=',
            'ne' => '<>',
            'lt' => '<',
            'gt' => '>',
        ];
        foreach ($params as $key => $val) {
            if (is_null($val) or strpos($key, '_') === 0) {
                continue;
            }
            $__pos = strpos($key, '__');
            if ($__pos > 0) {
                $operation = substr($key, $__pos + 2);
                $key = substr($key, 0, $__pos);
                switch ($operation) {
                    case 'in':
                        if (!is_array($val)) {
                            $val = explode(',', $val);
                        }
                        $query->whereIn($key, $val);
                        break;
                    case 'notin':
                        if (!is_array($val)) {
                            $val = explode(',', $val);
                        }
                        $query->whereNotIn($key, $val);
                        break;
                    case 'e':
                    case 'lte':
                    case 'gte':
                    case 'ne':
                    case 'lt':
                    case 'gt':
                        $query->where($key, $operations[$operation], $val);
                        break;
                    case 'null':
                        $query->whereNull($key);
                        break;
                    case 'notnull':
                        $query->whereNotNull($key);
                        break;
                    case 'like':
                        $query->where($key, 'like', $val);
                        break;
                    case 'notlike':
                        $query->where($key, 'not like', $val);
                        break;
                }
            } else {
                $query->where($key, '=', $val);
            }
        }

        //sort
        $sorts = array_get($params, '_sort');
        if (is_array($sorts)) {
            foreach ($sorts as $field => $direction) {
                $direction = $direction < 0 ? 'desc' : 'asc';
                $query->orderBy($field, $direction);
            }
        }

        return $query;
    }

    public function multiSearch(Builder $query, array $params)
    {
        $perPage = (int)array_get($params, '_page_size');
        $perPage = min($perPage, '120');
        if (!$perPage) {
            $perPage = 120;
        }
        $result['page_size'] = $perPage;

        $page = (int)array_get($params, '_page');
        $page = $page ?: 1;
        $result['page'] = $page;

        unset($params['_page_size']);
        unset($params['_page']);

        $query = $this->buildMultiQuery($query, $params);

        $result['count'] = 0;
        //get count before pegination
        if (!array_get($params, '_group')) {
            $result['total'] = $query->count();
        }

        $query->skip(($page - 1) * $perPage);
        $result['list'] = $query->take($perPage)->get()->toArray();

        if (array_get($params, '_group') and array_get($params, '_group_count')) {
            $result['total'] = DB::select(DB::raw('SELECT FOUND_ROWS() as rows;'))[0]->rows;
        }

        foreach ($result['list'] as $index => $row) {
            foreach ($row as $key => $val) {
                if (is_null($val)) {
                    $result['list'][$index][$key] = '';
                }
            }
        }

        return $result;
    }

    public function multiSearchWithoutPage(Builder $query, array $params)
    {
        $query = $this->buildMultiQuery($query, $params);
        $result = $query->get()->toArray();
        foreach ($result as $index => $row) {
            foreach ($row as $key => $value) {
                if (is_null($value)) {
                    $result[$index][$key] = '';
                }
            }
        }
        return $result;
    }
}
